package com.xdcplus.web.service.alarm.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.exceptions.XdcWebException;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.FileType;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.web.common.constants.BisDataCateConstants;
import com.xdcplus.web.common.pojo.dto.alarm.ImportToolAlarmCodeDto;
import com.xdcplus.web.common.pojo.dto.alarm.ToolAlarmCodeDTO;
import com.xdcplus.web.common.pojo.dto.alarm.ToolAlarmCodeFilterDTO;
import com.xdcplus.web.common.pojo.dto.alarm.ToolAlarmCodeUpdateDTO;
import com.xdcplus.web.common.pojo.entity.alarm.ToolAlarmCode;
import com.xdcplus.web.common.pojo.entity.alarm.ToolAlarmGroup;
import com.xdcplus.web.common.pojo.entity.sys.SysDepartment;
import com.xdcplus.web.common.pojo.query.alarm.ToolAlarmCodeQuery;
import com.xdcplus.web.common.pojo.vo.alarm.ToolAlarmCodeExportVO;
import com.xdcplus.web.common.pojo.vo.alarm.ToolAlarmCodeVO;
import com.xdcplus.web.common.pojo.vo.sys.SysDepartmentVO;
import com.xdcplus.web.mapper.alarm.ToolAlarmCodeMapper;
import com.xdcplus.web.service.alarm.ToolAlarmCodeService;
import com.xdcplus.web.service.alarm.ToolAlarmGroupService;
import com.xdcplus.web.service.sys.SysBaseDataService;
import com.xdcplus.web.service.sys.SysDepartmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备告警码表(ToolAlarmCode)表服务实现类
 *
 * @author bullion.yan
 * @since 2024-06-05 16:16:14
 */
@Slf4j
@Service("toolAlarmCodeService")
public class ToolAlarmCodeServiceImpl extends BaseServiceImpl<ToolAlarmCodeMapper, ToolAlarmCode, ToolAlarmCode, ToolAlarmCodeVO> implements ToolAlarmCodeService {

    @Autowired
    protected ToolAlarmCodeMapper toolAlarmCodeMapper;
    @Autowired
    private ToolAlarmGroupService toolAlarmGroupService;
    @Autowired
    private SysBaseDataService sysBaseDataService;
    @Autowired
    private SysDepartmentService sysDepartmentService;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveToolAlarmCode(ToolAlarmCodeDTO toolAlarmCodeDTO) {
        ToolAlarmGroup toolAlarmGroup= toolAlarmGroupService.getById(toolAlarmCodeDTO.getGroupIdFk());
        Assert.notNull(toolAlarmGroup, ResponseEnum.THE_ALARM_GROUP_DOES_NOT_EXIST.getMessage());
        ToolAlarmCode toolAlarmCode = new ToolAlarmCode();
        BeanUtil.copyProperties(toolAlarmCodeDTO, toolAlarmCode);
        toolAlarmCode.setCreatedTime(new Timestamp(DateUtil.current()));
        validateAlarmCodeIsExists(toolAlarmCode);
        return this.save(toolAlarmCode);
    }


    private void validateAlarmCodeIsExists(ToolAlarmCode toolAlarmCode) {
        ToolAlarmCode toolAlarmCodeExists = toolAlarmCodeMapper.queryToolAlarmCodeByAlarmCode(toolAlarmCode.getAlarmCode());
        if(toolAlarmCodeExists != null && (!toolAlarmCodeExists.getId().equals(toolAlarmCode.getId()))){
            throw new XdcWebException(ResponseEnum.ERROR,String.format("告警码:%s已经存在",toolAlarmCode.getAlarmCode()));
        }
    }
    @Override
    public List<ToolAlarmCode> queryByGroupIdFk(Long groupIdFk) {
        return toolAlarmCodeMapper.queryByGroupIdFk(groupIdFk);
    }
    @Override
    public List<ToolAlarmCodeExportVO> queryExportToolAlarmCode(Long groupIdFk) {
       Map<String,String > faultTypeMap=sysBaseDataService.getCodeMapByDataCate(BisDataCateConstants.FAULT_TYPE);
       Map<String,String > toolAlarmGradeList= sysBaseDataService.getCodeMapByDataCate(BisDataCateConstants.TOOL_ALARM_GRADE);
        List<ToolAlarmCodeExportVO>  toolAlarmCodeExportVOList=toolAlarmCodeMapper.queryExportToolAlarmCode(groupIdFk);
        if(CollectionUtil.isNotEmpty(toolAlarmCodeExportVOList)){
            for(ToolAlarmCodeExportVO toolAlarmCodeExportVO:toolAlarmCodeExportVOList){
                toolAlarmCodeExportVO.setFaultType(toolAlarmCodeExportVO.getFaultType()!=null?faultTypeMap.get(toolAlarmCodeExportVO.getFaultType()):"");
                toolAlarmCodeExportVO.setAlarmGrade(toolAlarmCodeExportVO.getAlarmGrade()!=null?toolAlarmGradeList.get(toolAlarmCodeExportVO.getAlarmGrade()):"");
            }
        }
        return toolAlarmCodeExportVOList;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean updateToolAlarmCode(ToolAlarmCodeUpdateDTO toolAlarmCodeUpdateDTO) {
        ToolAlarmCode toolAlarmCode =  this.getById(toolAlarmCodeUpdateDTO.getId());
        if (ObjectUtil.isNull(toolAlarmCode)) {
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        BeanUtil.copyProperties(toolAlarmCodeUpdateDTO, toolAlarmCode);
        toolAlarmCode.setUpdatedUser(toolAlarmCodeUpdateDTO.getUpdatedUser());
        toolAlarmCode.setUpdatedTime(new Timestamp(DateUtil.current()));
        return this.updateById(toolAlarmCode);
    }

    @Override
    public Boolean saveOrUpdateBatch(List<ToolAlarmCode> toolAlarmCodeList) {

        toolAlarmCodeList.forEach(toolAlarmCode -> {
            ToolAlarmCode toolAlarmCodeParam = new ToolAlarmCode();
            toolAlarmCodeParam.setId(toolAlarmCode.getId());
            if (ObjectUtil.isNotNull(toolAlarmCode.getId())) {
                toolAlarmCode.setId(toolAlarmCode.getId());
                toolAlarmCode.setUpdatedTime(new Timestamp(DateUtil.current()));
                LambdaUpdateWrapper<ToolAlarmCode> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(ToolAlarmCode::getId, toolAlarmCode.getId());
                update(toolAlarmCode, lambdaUpdate);
            } else {
                toolAlarmCode.setCreatedTime(new Timestamp(DateUtil.current()));
                save(toolAlarmCode);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<ToolAlarmCodeDTO> toolAlarmCodeDTOList) {
        List<ToolAlarmCode> toolAlarmCodeList = BeanUtils.copyProperties(toolAlarmCodeDTOList, ToolAlarmCode.class);
        return saveOrUpdateBatch(toolAlarmCodeList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteToolAlarmCodeLogical(Long id) {
        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        ToolAlarmCode toolAlarmCode = this.getById(id);
        if (ObjectUtil.isNull(toolAlarmCode)) {
            log.error("deleteToolAlarmCode() The ToolAlarmCode does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        return this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteToolAlarmCodeByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
		List<String> idList = Arrays.asList(ids.split(","));
		if(CollectionUtil.isEmpty(idList)){
           throw new XdcWebException(ResponseEnum.ERROR);
       }
		idList.forEach(id->{
			ToolAlarmCode toolAlarmCode = this.getById(id);
			if (ObjectUtil.isNull(toolAlarmCode)) {
				log.error("deleteToolAlarmCode() The ToolAlarmCode does not exist or has been deleted");
				throw new XdcWebException(ResponseEnum.ERROR);
			}
		});

        return this.removeByIds(idList);
    }

    private List<ToolAlarmCode> queryToolAlarmCodeList(ToolAlarmCodeFilterDTO toolAlarmCodeFilterDTO) {
        ToolAlarmCodeQuery toolAlarmCodeQuery = BeanUtil.copyProperties(toolAlarmCodeFilterDTO, ToolAlarmCodeQuery.class);

        return toolAlarmCodeMapper.queryToolAlarmCode(toolAlarmCodeQuery);
    }

    @Override
    public List<ToolAlarmCodeVO> queryToolAlarmCodeVOList(ToolAlarmCodeFilterDTO toolAlarmCodeFilterDTO) {
        return this.objectConversion(queryToolAlarmCodeList(toolAlarmCodeFilterDTO));
    }

    @Override
    public PageVO<ToolAlarmCodeVO> queryToolAlarmCode(ToolAlarmCodeFilterDTO toolAlarmCodeFilterDTO) {
        PageVO<ToolAlarmCodeVO> pageVO = new PageVO<>();

        if (toolAlarmCodeFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageHelper.startPage(toolAlarmCodeFilterDTO.getCurrentPage(), toolAlarmCodeFilterDTO.getPageSize());
        }
        List<ToolAlarmCode> toolAlarmCodeList = queryToolAlarmCodeList(toolAlarmCodeFilterDTO);
        PageInfo<ToolAlarmCode> pageInfo = new PageInfo<>(toolAlarmCodeList);
        PropertyUtils.copyProperties(pageInfo, pageVO, this.objectConversion(toolAlarmCodeList));

        return pageVO;
    }

    @Override
    public ToolAlarmCodeVO objectConversion(ToolAlarmCode toolAlarmCode) {
        ToolAlarmCodeVO toolAlarmCodeVO= super.objectConversion(toolAlarmCode);
        if(toolAlarmCodeVO!=null && toolAlarmCode.getFaultDepartmentIdFk()!=null){
            SysDepartmentVO sysDepartmentVO= sysDepartmentService.querySysDepartmentById(toolAlarmCode.getFaultDepartmentIdFk());
            if(sysDepartmentVO!=null){
             toolAlarmCodeVO.setFaultDepartmentName(sysDepartmentVO.getName());
            }
        }
        return toolAlarmCodeVO;
    }

    @Override
    public ToolAlarmCodeVO queryToolAlarmCodeById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public void importAlarmCode(MultipartFile file, Long groupIdFk, HttpServletResponse response, String operatorUserName) throws IOException {
        ToolAlarmGroup toolAlarmGroup = toolAlarmGroupService.getById(groupIdFk);
        Assert.notNull(toolAlarmGroup, "告警组不存在");
        final List<ImportToolAlarmCodeDto> importToolInspectionItemDtoList = new ArrayList<>();
        EasyExcel.read(file.getInputStream(),
                ImportToolAlarmCodeDto.class, new ReadListener<ImportToolAlarmCodeDto>() {
                    @Override
                    public void onException(Exception exception, AnalysisContext context) throws Exception {
                        ReadListener.super.onException(exception, context);
                    }

                    @Override
                    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                        ReadListener.super.invokeHead(headMap, context);
                    }
                    @Override
                    public void invoke(ImportToolAlarmCodeDto importToolInspectionItemDto, AnalysisContext analysisContext) {
                        importToolInspectionItemDtoList.add(importToolInspectionItemDto);
                    }
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                    }
                }).sheet(0).headRowNumber(1).doRead();
        // 验证导入的数据是否存在
        if (importToolInspectionItemDtoList.isEmpty()) {
            throw new XdcWebException(ResponseEnum.FILE_ISBLANK);
        }
        Map<String,String > faultTypeMap=sysBaseDataService.getDescMapByDataCate(BisDataCateConstants.FAULT_TYPE);
        Map<String,String > toolAlarmGradeList= sysBaseDataService.getDescMapByDataCate(BisDataCateConstants.TOOL_ALARM_GRADE);
        List<ToolAlarmCode>  toolAlarmCodeList=new ArrayList<>();
        Map<String,Long> departMap=new HashMap<>();
        //重复的值覆盖,导入只做新增和更新
        for (Integer i = 0; i < importToolInspectionItemDtoList.size(); i++) {
            ImportToolAlarmCodeDto importToolInspectionItemDto = importToolInspectionItemDtoList.get(i);
            ToolAlarmCode toolAlarmCode= BeanUtil.copyProperties(importToolInspectionItemDto, ToolAlarmCode.class);
            if(importToolInspectionItemDto.getIsFaultDesc()!=null && importToolInspectionItemDto.getIsFaultDesc().equals("是")){
                toolAlarmCode.setIsFault(1L);
            }else if(importToolInspectionItemDto.getIsFaultDesc()!=null && importToolInspectionItemDto.getIsFaultDesc().equals("否")){
                toolAlarmCode.setIsFault(0L);
            }
            //设置告警等级
            toolAlarmCode.setAlarmGrade(toolAlarmGradeList.get(importToolInspectionItemDto.getAlarmGrade()));
            //故障类型
            toolAlarmCode.setFaultType(faultTypeMap.get(importToolInspectionItemDto.getFaultType()));
            //故障部门
            if(StringUtils.isNotEmpty(importToolInspectionItemDto.getFaultDepartment())){
                if(departMap.get(importToolInspectionItemDto.getFaultDepartment())!=null){
                    toolAlarmCode.setFaultDepartmentIdFk(departMap.get(importToolInspectionItemDto.getFaultDepartment()));
                }else{
                    SysDepartment sysDepartment= sysDepartmentService.querySysDepartmentByName(importToolInspectionItemDto.getFaultDepartment());
                    Assert.notNull(sysDepartment,String.format("故障部门%s不存在",importToolInspectionItemDto.getFaultDepartment()));
                        toolAlarmCode.setFaultDepartmentIdFk(sysDepartment.getId());
                        departMap.put(importToolInspectionItemDto.getFaultDepartment(),sysDepartment.getId());
                }
            }
            Assert.notEmpty(toolAlarmCode.getAlarmCode(),String.format("第%s行的告警码不能为空",i+2));
            Assert.notEmpty(toolAlarmCode.getAlarmContent(),String.format("第%s行的告警内容不能为空",i+2));
            Assert.notEmpty(toolAlarmCode.getFaultType(),String.format("第%s行的故障类型不能为空",i+2));
            Assert.notEmpty(toolAlarmCode.getAlarmGrade(),String.format("第%s行的告警等级不能为空",i+2));
            Assert.notNull(toolAlarmCode.getIsFault(),String.format("第%s行的是否报修不能为空",i+2));
            toolAlarmCode.setCreatedUser(operatorUserName);
            toolAlarmCode.setCreatedTime(Timestamp.from(Instant.now()));
            toolAlarmCode.setUpdatedUser(operatorUserName);
            toolAlarmCode.setUpdatedTime(Timestamp.from(Instant.now()));
            toolAlarmCode.setGroupIdFk(groupIdFk);
            validateAlarmCodeIsExists(toolAlarmCode);
            toolAlarmCodeList.add(toolAlarmCode);
        }
        Map<String, List<ToolAlarmCode>> sumToItemsMap = toolAlarmCodeList.stream()
                .collect(Collectors.groupingBy(e->e.getAlarmCode(), Collectors.toList()));
        if(sumToItemsMap.values().stream()
                .anyMatch(itemList -> itemList.size() > 1)){
            throw new XdcWebException(ResponseEnum.ERROR,"导入的Excel数据中有重复的告警码存在，导入失败");
        }
        /// 批量保存和更新
        this.saveBatch(toolAlarmCodeList);
    }

    @Override
    public void exportAlarmCode(Long groupIdFk, HttpServletResponse response, String operatorUserName) throws IOException {
        ToolAlarmGroup toolAlarmGroup = toolAlarmGroupService.getById(groupIdFk);
        Assert.notNull(toolAlarmGroup, "告警组不存在");
        List<ToolAlarmCodeExportVO> toolAlarmCodeList = this.queryExportToolAlarmCode(groupIdFk);
        response.setContentType(FileType.XLSX.getValue());
        response.setHeader("Content-Disposition", "attachment; filename="+toolAlarmGroup.getToolGroupName()+".xls");
        ServletOutputStream outputStream = response.getOutputStream();
        EasyExcel.write(outputStream, ToolAlarmCodeExportVO.class).registerWriteHandler(new SimpleColumnWidthStyleStrategy(18)).sheet("数据导出").doWrite(toolAlarmCodeList);
    }

    @Override
    public List<ToolAlarmCode> queryByAlarmCodeList(List<String> alarmCodeList) {
        return toolAlarmCodeMapper.selectList(new QueryWrapper<ToolAlarmCode>().in("ALARM_CODE",alarmCodeList));
    }

    @Override
    public ToolAlarmCodeVO queryToolAlarmCodeByAlarmCode(String alarmCode) {
        Assert.notBlank(alarmCode, ResponseEnum.THE_CODE_CANNOT_BE_EMPTY.getMessage());
        return this.objectConversion(toolAlarmCodeMapper.queryToolAlarmCodeByAlarmCode(alarmCode));
    }

}
